

/**
 * @file ComputeLinear.cpp
 * This class computes linear combinations of GDS data.
 */

//============================================================================
//
//  This file is part of GPSTk, the GPS Toolkit.
//
//  The GPSTk is free software; you can redistribute it and/or modify
//  it under the terms of the GNU Lesser General Public License as published
//  by the Free Software Foundation; either version 2.1 of the License, or
//  any later version.
//
//  The GPSTk is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with GPSTk; if not, write to the Free Software Foundation,
//  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
//
//  Dagoberto Salazar - gAGE ( http://www.gage.es ). 2007, 2008, 2011
//
//============================================================================


#include "ComputeLinear.hpp"

using namespace std;

#define debug 0

namespace gpstk
{

      // Return a string identifying this object.
    std::string ComputeLinear::getClassName() const
    { return "ComputeLinear"; }



      /* Return a satTypeValueMap object, adding the new data generated when
       * calling this object.
       *
       * @param time      Epoch corresponding to the data.
       * @param gData     Data object holding the data.
       */
    satTypeValueMap& ComputeLinear::Process( const CommonTime& time,
                                             satTypeValueMap& gData )
        noexcept(false)
    {

        try
        {
            SatIDSet satRejectedSet;
            LinearCombList linearList;

            // Loop through all the satellites
            for(satTypeValueMap::iterator it = gData.begin();
                it != gData.end();
                ++it)
            {
                SatID sat = (*it).first;

                if(debug)
                {
                    cout << "sat:" << sat << endl;
                }

                if(sat.system == SatelliteSystem::GPS)
                {
                    linearList = linearListOfGPS;
                }
                else if(sat.system == SatelliteSystem::Galileo)
                {
                    linearList = linearListOfGAL;
                }
                else if(sat.system == SatelliteSystem::BDS)
                {
                    linearList = linearListOfBDS;
                }

                  // if combinations is not given for current system, 
                  // it means that the satellites for current system will be removed
                if(linearList.empty())
                {
                    satRejectedSet.insert(sat);
                }

                // Loop through all the defined linear combinations
                for(LinearCombList::const_iterator pos = linearList.begin();
                    pos != linearList.end();
                    ++pos)
                {
                    double result(0.0);

                    bool found( true );

                    if(debug)
                        cout << pos->header << endl;

                    // Read the information of each linear combination
                    for(typeValueMap::const_iterator iter = pos->body.begin();
                        iter != pos->body.end();
                        ++iter)
                    {
                        double temp(0.0);

                        TypeID type(iter->first);
                        if( (*it).second.find(type) != (*it).second.end() )
                        {
                            temp = (*it).second[type];
                        }
                        else
                        {
                            if(optTypeSet.find(type) == optTypeSet.end())
                            {
                                found = false;
                            }
                        }

                        if(debug)
                            cout << type << " value: " << temp << endl;

                        result = result + (*iter).second * temp;
                    }

                    // Store the result in the proper place
                    if( found )
                    {
                        (*it).second[pos->header] = result;
                    }
                }
            }

               // Remove satellites with missing data
            gData.removeSatID(satRejectedSet);

            return gData;

        }
        catch(Exception& u)
        {
            // Throw an exception if something unexpected happens
            ProcessingException e( getClassName() + ":" + u.what() );
            GPSTK_THROW(e);
        }

    }  // End of method 'ComputeLinear::Process()'



     /** Return a sourceRinex object, adding the new data generated
      *  when calling this object.
      *
      * @param gData    Data object holding the data.
      */
    void ComputeLinear::Process(commonHeader& comHeader, sourceRinex& gData)
        noexcept(false)
    {
        for(sourceDataMap::iterator sdmIt = gData.body.begin();
            sdmIt != gData.body.end();
            ++sdmIt)
        {
            Process( gData.header.epoch, sdmIt->second );
        }

    }  // End of method 'ComputeLinear::Process()'


} // End of namespace gpstk
